DETTEN CRACKME #12 ****************** Cracker: figugegl Email: figugegl_2000@yahoo.de Date: 21.1.2002 Tools: Softice, IDA Level 1-10: 5 This ASM-Crackme has an unusual protection: Out of 15 buttons we have to press the right ones to enter a 10-digit keycode. It took me a while to fully understand what's going on here and how to solve it. The readme-file is a little misleading, Detten says: "Don't try to bruteforce all combinations, too much work! Instead try to figure out the 'holes' in the code". But we do have to bruteforce to get the valid combination. Letīs have a look at the listing first, especially the part where the buttons are being processed with the WM_COMMAND message. Due to the number of buttons, the listing is quite big: 0040102E 81 7D 0C 10 01 00+ cmp [ebp+arg_4], 110h ; WM_INITDIALOG 00401035 75 37 jnz short loc_40106E 00401037 C7 05 48 30 40 00+ mov dword_403048, 0 ; loopcounter = 0 00401041 C7 05 38 30 40 00+ mov dword_403038, 0DEADh ; a = 0DEADh 0040104B C7 05 3C 30 40 00+ mov dword_40303C, 0DEADh ; b = 0DEADh 00401055 C7 05 40 30 40 00+ mov dword_403040, 42424242h ; c = 42424242h 0040105F C7 05 4C 30 40 00+ mov dword_40304C, offset aAnErrorOccured ; ASCII 'An error occured' 00401069 E9 DE 01 00 00 jmp loc_40124C 0040106E ; --------------------------------------------------------------------------- 0040106E 83 7D 0C 10 cmp [ebp+arg_4], 10h ; WM_CLOSE 00401072 75 0D jnz short loc_401081 00401074 FF 75 08 push [ebp+arg_0] ; hWnd 00401077 E8 32 04 00 00 call j_DestroyWindow ; DestroyWindow 0040107C E9 CB 01 00 00 jmp loc_40124C 00401081 ; --------------------------------------------------------------------------- 00401081 81 7D 0C 11 01 00+ cmp [ebp+arg_4], 111h ; WM_COMMAND 00401088 0F 85 B5 01 00 00 jnz loc_401243 0040108E 8B 45 10 mov eax, [ebp+arg_8] 00401091 8B 55 10 mov edx, [ebp+arg_8] 00401094 C1 EA 10 shr edx, 10h 00401097 66 0B D2 or dx, dx 0040109A 0F 85 AC 01 00 00 jnz loc_40124C 004010A0 66 83 F8 65 cmp ax, 65h ; Button '1' ? 004010A4 75 0C jnz short loc_4010B2 004010A6 6A 01 push 1 004010A8 E8 F8 01 00 00 call sub_4012A5 ; call 1 004010AD E9 40 01 00 00 jmp loc_4011F2 004010B2 ; --------------------------------------------------------------------------- 004010B2 66 83 F8 66 cmp ax, 66h ; Button '2' ? 004010B6 75 0C jnz short loc_4010C4 004010B8 6A 02 push 2 004010BA E8 E6 01 00 00 call sub_4012A5 ; call 1 004010BF E9 2E 01 00 00 jmp loc_4011F2 004010C4 ; --------------------------------------------------------------------------- 004010C4 66 83 F8 67 cmp ax, 67h ; Button '3' ? 004010C8 75 0C jnz short loc_4010D6 004010CA 6A 03 push 3 004010CC E8 D4 01 00 00 call sub_4012A5 ; call 1 004010D1 E9 1C 01 00 00 jmp loc_4011F2 004010D6 ; --------------------------------------------------------------------------- 004010D6 66 83 F8 68 cmp ax, 68h ; Button '4' ? 004010DA 75 0C jnz short loc_4010E8 004010DC 6A 04 push 4 004010DE E8 C2 01 00 00 call sub_4012A5 ; call 1 004010E3 E9 0A 01 00 00 jmp loc_4011F2 004010E8 ; --------------------------------------------------------------------------- 004010E8 66 83 F8 69 cmp ax, 69h ; Button '5' ? 004010EC 75 0C jnz short loc_4010FA 004010EE 6A 05 push 5 004010F0 E8 B0 01 00 00 call sub_4012A5 ; call 1 004010F5 E9 F8 00 00 00 jmp loc_4011F2 004010FA ; --------------------------------------------------------------------------- 004010FA 66 83 F8 6A cmp ax, 6Ah ; Button '6' ? 004010FE 75 0C jnz short loc_40110C 00401100 6A 06 push 6 00401102 E8 9E 01 00 00 call sub_4012A5 ; call 1 00401107 E9 E6 00 00 00 jmp loc_4011F2 0040110C ; --------------------------------------------------------------------------- 0040110C 66 83 F8 6B cmp ax, 6Bh ; Button '7' ? 00401110 75 0C jnz short loc_40111E 00401112 6A 07 push 7 00401114 E8 8C 01 00 00 call sub_4012A5 ; call 1 00401119 E9 D4 00 00 00 jmp loc_4011F2 0040111E ; --------------------------------------------------------------------------- 0040111E 66 83 F8 6C cmp ax, 6Ch ; Button '8' ? 00401122 75 0C jnz short loc_401130 00401124 6A 08 push 8 00401126 E8 7A 01 00 00 call sub_4012A5 ; call 1 0040112B E9 C2 00 00 00 jmp loc_4011F2 00401130 ; --------------------------------------------------------------------------- 00401130 66 83 F8 6D cmp ax, 6Dh ; Button '9' ? 00401134 75 0C jnz short loc_401142 00401136 6A 09 push 9 00401138 E8 68 01 00 00 call sub_4012A5 ; call 1 0040113D E9 B0 00 00 00 jmp loc_4011F2 00401142 ; --------------------------------------------------------------------------- 00401142 66 83 F8 6E cmp ax, 6Eh ; Button '10' ? 00401146 75 0C jnz short loc_401154 00401148 6A 0A push 0Ah 0040114A E8 56 01 00 00 call sub_4012A5 ; call 1 0040114F E9 9E 00 00 00 jmp loc_4011F2 00401154 ; --------------------------------------------------------------------------- 00401154 66 83 F8 6F cmp ax, 6Fh ; Button '11' ? 00401158 75 0C jnz short loc_401166 0040115A 6A 0B push 0Bh 0040115C E8 44 01 00 00 call sub_4012A5 ; call 1 00401161 E9 8C 00 00 00 jmp loc_4011F2 00401166 ; --------------------------------------------------------------------------- 00401166 66 83 F8 70 cmp ax, 70h ; Button '12' ? 0040116A 75 09 jnz short loc_401175 0040116C 6A 0C push 0Ch 0040116E E8 32 01 00 00 call sub_4012A5 ; call 1 00401173 EB 7D jmp short loc_4011F2 00401175 ; --------------------------------------------------------------------------- 00401175 66 83 F8 71 cmp ax, 71h ; Button '13' ? 00401179 75 09 jnz short loc_401184 0040117B 6A 0D push 0Dh 0040117D E8 23 01 00 00 call sub_4012A5 ; call 1 00401182 EB 6E jmp short loc_4011F2 00401184 ; --------------------------------------------------------------------------- 00401184 66 83 F8 72 cmp ax, 72h ; Button '14' ? 00401188 75 09 jnz short loc_401193 0040118A 6A 0E push 0Eh 0040118C E8 14 01 00 00 call sub_4012A5 ; call 1 00401191 EB 5F jmp short loc_4011F2 00401193 ; --------------------------------------------------------------------------- 00401193 66 83 F8 73 cmp ax, 73h ; Button '15' ? 00401197 75 09 jnz short loc_4011A2 00401199 6A 0F push 0Fh 0040119B E8 05 01 00 00 call sub_4012A5 ; call 1 004011A0 EB 50 jmp short loc_4011F2 Depending on which button has been pressed, a number is pushed on the stack for call 1. What happens there? 004012A9 8B 0D 40 30 40 00 mov ecx, dword_403040 ; a 004012AF 8B 1D 3C 30 40 00 mov ebx, dword_40303C ; b 004012B5 A1 38 30 40 00 mov eax, dword_403038 ; c 004012BA 80 7D 08 01 cmp [ebp+arg_0], 1 ; Button 1 004012BE 75 10 jnz short loc_4012D0 004012C0 81 C1 4B 05 00 00 add ecx, 54Bh ; c += 54Bh 004012C6 0F AF D8 imul ebx, eax ; b *= a 004012C9 33 C1 xor eax, ecx ; a^= c 004012CB E9 17 01 00 00 jmp loc_4013E7 004012D0 ; --------------------------------------------------------------------------- 004012D0 80 7D 08 02 cmp [ebp+arg_0], 2 ; Button 2 004012D4 75 12 jnz short loc_4012E8 004012D6 81 E9 33 02 00 00 sub ecx, 233h ; c -= 233h 004012DC 6B DB 14 imul ebx, 14h ; b *= 14h 004012DF 03 C8 add ecx, eax ; c += a 004012E1 23 D8 and ebx, eax ; b &= a 004012E3 E9 FF 00 00 00 jmp loc_4013E7 004012E8 ; --------------------------------------------------------------------------- 004012E8 80 7D 08 03 cmp [ebp+arg_0], 3 ; Button 3 004012EC 75 0F jnz short loc_4012FD 004012EE 05 82 05 00 00 add eax, 582h ; a += 582h 004012F3 6B C9 16 imul ecx, 16h ; c *= 16h 004012F6 33 D8 xor ebx, eax ; b ^= a 004012F8 E9 EA 00 00 00 jmp loc_4013E7 004012FD ; --------------------------------------------------------------------------- 004012FD 80 7D 08 04 cmp [ebp+arg_0], 4 ; Button 4 00401301 75 0F jnz short loc_401312 00401303 23 C3 and eax, ebx ; a &= b 00401305 81 EB 22 12 11 00 sub ebx, 111222h ; b -= 111222h 0040130B 33 C8 xor ecx, eax ; c ^= a 0040130D E9 D5 00 00 00 jmp loc_4013E7 00401312 ; --------------------------------------------------------------------------- 00401312 80 7D 08 05 cmp [ebp+arg_0], 5 ; Button 5 00401316 75 0C jnz short loc_401324 00401318 99 cdq 00401319 F7 F9 idiv ecx ; a /= c, division rest --> (r) 0040131B 2B DA sub ebx, edx ; b -= r 0040131D 03 C1 add eax, ecx ; a += c 0040131F E9 C3 00 00 00 jmp loc_4013E7 00401324 ; --------------------------------------------------------------------------- 00401324 80 7D 08 06 cmp [ebp+arg_0], 6 ; Button 6 00401328 75 0F jnz short loc_401339 0040132A 33 C1 xor eax, ecx ; a ^= c 0040132C 23 D8 and ebx, eax ; b &= a 0040132E 81 C1 79 68 54 00 add ecx, 546879h ; c += 546879h 00401334 E9 AE 00 00 00 jmp loc_4013E7 00401339 ; --------------------------------------------------------------------------- 00401339 80 7D 08 07 cmp [ebp+arg_0], 7 ; Button 7 0040133D 75 12 jnz short loc_401351 0040133F 81 E9 F5 5F 02 00 sub ecx, 25FF5h ; c -= 25FF5h 00401345 33 D9 xor ebx, ecx ; b ^= c 00401347 05 00 10 40 00 add eax, 401000h ; a += 401000h 0040134C E9 96 00 00 00 jmp loc_4013E7 00401351 ; --------------------------------------------------------------------------- 00401351 80 7D 08 08 cmp [ebp+arg_0], 8 ; Button 8 00401355 75 10 jnz short loc_401367 00401357 33 C1 xor eax, ecx ; a ^= c 00401359 6B DB 14 imul ebx, 14h ; b *= 14h 0040135C 81 C1 89 25 01 00 add ecx, 12589h ; c += 12589h 00401362 E9 80 00 00 00 jmp loc_4013E7 00401367 ; --------------------------------------------------------------------------- 00401367 80 7D 08 09 cmp [ebp+arg_0], 9 ; Button 9 0040136B 75 0B jnz short loc_401378 0040136D 2D 87 21 54 00 sub eax, 542187h ; a -= 542187h 00401372 2B D8 sub ebx, eax ; b -= a 00401374 33 C8 xor ecx, eax ; c ^= a 00401376 EB 6F jmp short loc_4013E7 00401378 ; --------------------------------------------------------------------------- 00401378 80 7D 08 0A cmp [ebp+arg_0], 0Ah ; Button 10 0040137C 75 0C jnz short loc_40138A 0040137E 99 cdq 0040137F F7 FB idiv ebx ; a /= b, division rest --> (r) 00401381 03 DA add ebx, edx ; b += r 00401383 0F AF C2 imul eax, edx ; a *= r 00401386 33 CA xor ecx, edx ; c ^= r 00401388 EB 5D jmp short loc_4013E7 0040138A ; --------------------------------------------------------------------------- 0040138A 80 7D 08 0B cmp [ebp+arg_0], 0Bh ; Button 11 0040138E 75 13 jnz short loc_4013A3 00401390 81 C3 FE 34 12 00 add ebx, 1234FEh ; b += 1234FEh 00401396 81 C1 DE 45 23 00 add ecx, 2345DEh ; c += 2345DEh 0040139C 05 9B 43 A4 9C add eax, 9CA4439Bh ; a += 9CA4439Bh 004013A1 EB 44 jmp short loc_4013E7 004013A3 ; --------------------------------------------------------------------------- 004013A3 80 7D 08 0C cmp [ebp+arg_0], 0Ch ; Button 12 004013A7 75 09 jnz short loc_4013B2 004013A9 33 C3 xor eax, ebx ; a ^= b 004013AB 2B D9 sub ebx, ecx ; b -= c 004013AD 6B C9 12 imul ecx, 12h ; c *= 12h 004013B0 EB 35 jmp short loc_4013E7 004013B2 ; --------------------------------------------------------------------------- 004013B2 80 7D 08 0D cmp [ebp+arg_0], 0Dh ; Button 13 004013B6 75 10 jnz short loc_4013C8 004013B8 25 78 56 34 12 and eax, 12345678h ; a &= 12345678h 004013BD 81 E9 75 58 06 00 sub ecx, 65875h ; c -= 65875h 004013C3 0F AF D9 imul ebx, ecx ; b *= c 004013C6 EB 1F jmp short loc_4013E7 004013C8 ; --------------------------------------------------------------------------- 004013C8 80 7D 08 0E cmp [ebp+arg_0], 0Eh ; Button 14 004013CC 75 0D jnz short loc_4013DB 004013CE 35 55 55 05 00 xor eax, 55555h ; a ^= 55555h 004013D3 81 EB 51 73 58 00 sub ebx, 587351h ; b -= 587351h 004013D9 EB 0C jmp short loc_4013E7 004013DB ; --------------------------------------------------------------------------- 004013DB 80 7D 08 0F cmp [ebp+arg_0], 0Fh ; Button 15 004013DF 75 06 jnz short loc_4013E7 004013E1 03 C3 add eax, ebx ; a += b 004013E3 03 D9 add ebx, ecx ; b += c 004013E5 03 C8 add ecx, eax ; c += a 004013E7 004013E7 FF 05 44 30 40 00 inc dword_403044 ; keycounter++ 004013ED A3 38 30 40 00 mov dword_403038, eax ; save a 004013F2 89 1D 3C 30 40 00 mov dword_40303C, ebx ; save b 004013F8 89 0D 40 30 40 00 mov dword_403040, ecx ; save c For every button pressed there are some calculations with the three variables a, b and c. They are saved and a counter is incremented. Back to the main program: 004011A2 66 83 F8 01 cmp ax, 1 ; Button "ABOUT" 004011A6 75 1C jnz short loc_4011C4 004011A8 6A 00 push 0 004011AA 68 55 12 40 00 push offset sub_401255 ; DlgProc = CRACKME1.00401255 004011AF FF 75 08 push [ebp+arg_0] ; hOwner 004011B2 68 BC 02 00 00 push 2BCh ; pTemplate = 2BC 004011B7 FF 35 28 30 40 00 push dword_403028 ; hInst = NULL 004011BD E8 F2 02 00 00 call j_DialogBoxParamA ; DialogBoxParamA 004011C2 EB 2E jmp short loc_4011F2 004011C4 ; --------------------------------------------------------------------------- 004011C4 66 83 F8 02 cmp ax, 2 ; Button "CLEAR" 004011C8 75 28 jnz short loc_4011F2 004011CA C7 05 38 30 40 00+ mov dword_403038, 0DEADh ; a = 0DEADh 004011D4 C7 05 3C 30 40 00+ mov dword_40303C, 0DEADh ; b = 0DEADh 004011DE C7 05 40 30 40 00+ mov dword_403040, 42424242h ; c = 42424242h 004011E8 C7 05 44 30 40 00+ mov dword_403044, 0 ; keycounter = 0 This section is pretty much self explanatory: when we press the About-button, the program shows the About box, and when we press the Clear-button, the three variables a, b, c and the loopcounter are reset. We're getting closer to the heart of the protection now: 004011F2 83 3D 48 30 40 00+ cmp dword_403048, 3 ; loopcounter >= 3 ? 004011F9 73 2D jnb short loc_401228 ; no, jump 004011FB 83 3D 44 30 40 00+ cmp dword_403044, 0Ah ; keycounter == 10 ? 00401202 75 3D jnz short loc_401241 ; no, jump 00401204 E8 43 02 00 00 call sub_40144C ; yes, call 2 00401209 68 00 30 40 00 push offset aAnErrorOccured ; ASCII 'An error occured' 0040120E FF 75 08 push [ebp+arg_0] ; hWnd 00401211 E8 ED 01 00 00 call sub_401403 ; call 3 00401216 C7 05 44 30 40 00+ mov dword_403044, 0 ; keycounter = 0 00401220 FF 05 48 30 40 00 inc dword_403048 ; loopcounter++ 00401226 EB 19 jmp short loc_401241 00401228 ; --------------------------------------------------------------------------- 00401228 68 11 30 40 00 push offset aTryingToBrutef ; Text = 'Trying to bruteforce?' 0040122D 6A 03 push 3 ; ControlID = 3 0040122F FF 75 08 push [ebp+arg_0] ; hWnd 00401232 E8 89 02 00 00 call j_SetDlgItemTextA ; SetDlgItemTextA 00401237 C7 05 44 30 40 00+ mov dword_403044, 0 ; keycounter = 0 00401241 EB 09 jmp short loc_40124C If the loopcounter is three, the program shows a nice message: 'Trying to bruteforce?' - I love Detten's humor :-)) We see that the length of the serial is 10, otherwise we jump over call 2 and 3. Call 2 is interesting: 0040144C 50 push eax 0040144D 68 50 30 40 00 push offset unk_403050 ; new access protection attributes 00401452 6A 04 push 4 ; NewProtect = PAGE_READWRITE 00401454 68 F4 01 00 00 push 1F4h ; Size = 1F4 (500.) 00401459 68 07 14 40 00 push offset loc_401407 ; Address = CRACKME1.00401407 0040145E E8 6F 00 00 00 call j_VirtualProtect ; protect address 401407 00401463 A1 38 30 40 00 mov eax, dword_403038 00401468 31 05 07 14 40 00 xor dword ptr ds:loc_401407, eax ; d ^= a 0040146E 80 3D 07 14 40 00+ cmp byte ptr ds:loc_401407, 52h ; d[0] == 52h ? 00401475 75 18 jnz short loc_40148F ; no: decryption failed, jump 00401477 A1 3C 30 40 00 mov eax, dword_40303C 0040147C 31 05 3B 14 40 00 xor ds:dword_40143B, eax ; yes: e ^= b 00401482 A1 40 30 40 00 mov eax, dword_403040 00401487 31 05 3F 14 40 00 xor ds:dword_40143F, eax ; f ^= c 0040148D EB 06 jmp short loc_401495 ; jump 0040148F 31 05 07 14 40 00 xor dword ptr ds:loc_401407, eax ; restore d in case decryption has failed 00401495 68 50 30 40 00 push offset unk_403050 ; restore access protection attributes 0040149A 6A 10 push 10h ; NewProtect = PAGE_EXECUTE 0040149C 68 F4 01 00 00 push 1F4h ; Size = 1F4 (500.) 004014A1 68 07 14 40 00 push offset loc_401407 ; Address = CRACKME1.00401407 004014A6 E8 27 00 00 00 call j_VirtualProtect ; protect address 401407 004014AB 58 pop eax 004014AC C3 retn Here we have some SMC - that's the whole trick. The three variables a, b and c are xored with the dwords at address 401407, 40143B and 40143F respectively. These addresses are in call 3. The first byte at address 401407 must be 52h. This is a security measure to check that everything has been well decrypted. Otherwise there might have been produced some garbage instructions that terminate the crackme with an error. Let's have a look at call 3: 00401403 55 push ebp 00401404 8B EC mov ebp, esp 00401406 50 push eax 00401407 EB 3F jmp short locret_401448 ; first dword to be decrypted --> (d) 00401409 90 nop ; 0040140A 90 nop ; 0040140B 42 inc edx 0040140C 8B 02 mov eax, [edx] ; decrypt string 0040140E 35 0D 43 00 01 xor eax, 100430Dh 00401413 89 02 mov [edx], eax 00401415 83 C2 04 add edx, 4 00401418 8B 02 mov eax, [edx] 0040141A 35 01 4F 15 52 xor eax, 52154F01h 0040141F 89 02 mov [edx], eax 00401421 83 C2 04 add edx, 4 00401424 8B 02 mov eax, [edx] 00401426 35 0E 0D 17 10 xor eax, 10170D0Eh 0040142B 89 02 mov [edx], eax 0040142D 83 C2 04 add edx, 4 00401430 8B 02 mov eax, [edx] 00401432 35 16 45 45 00 xor eax, 454516h 00401437 89 02 mov [edx], eax 00401439 5A pop edx 0040143A 58 pop eax 0040143A ; --------------------------------------------------------------------------- 0040143B 04 66 E7 BB dword_40143B dd 0BBE76604h ; second dword to be decrypted --> (e) 0040143F 4D BD 08 8B dword_40143F dd 8B08BD4Dh ; third dword to be decrypted --> (f) 00401443 ; --------------------------------------------------------------------------- 00401443 E8 78 00 00 00 call j_SetDlgItemTextA ; seems to be the success message 00401448 C9 leave 00401449 C2 08 00 retn 8 Well, this seems to be the success routine - the api function "SetDlgItemTextA" is very suspicious. We've learned in the call before that the three dwords at adress 401407, 40143B and 40143F are xored with variables, whose values depends on which keys have been pressed. We have to "guess" what instruction are missing in order to show a success message. First of all: Where is the success message? We find two arguments being pushed on the stack before the call: 00401209 68 00 30 40 00 push offset aAnErrorOccured ; ASCII 'An error occured' 0040120E FF 75 08 push [ebp+arg_0] ; hWnd 00401211 E8 ED 01 00 00 call sub_401403 ; call 3 Hmm, the string 'An error occured' - my Zen-instinct tells me that this is a fishy thing! We singlestep the routine, jump to address 40140B and change register edx to 403000, the offset of the string mentioned. And I was right, the decrypted string is "ACCESS GRANTED !". Well, that's a beginning. We now know, what should be displayed instead of "NO ACCESS". Fortunately, there's another "SetDlgItemTextA" in the main program, the one that shows the bruteforce message: 00401228 68 11 30 40 00 push offset aTryingToBrutef ; Text = 'Trying to bruteforce?' 0040122D 6A 03 push 3 ; ControlID = 3 0040122F FF 75 08 push [ebp+arg_0] ; hWnd 00401232 E8 89 02 00 00 call j_SetDlgItemTextA ; SetDlgItemTextA All we have to do is change the offset, all the other arguments are the same. The first and last one needed for the API function are being pushed in the main code (see above), we have to adjust call 3 accordingly. We know that byte 401407 has to be 52h, which is a "push edx" instruction. Then there are three bytes left, before the decryption of the string begins. This will only be done properly when register edx is the offset of the string, i.e. 403000. We have to load this into edx, but an ordinary mov edx, 403000 won't fit in three bytes. That's where the pushed arguments are needed. It's a ebp-based subroutine, and therefore we can find the pushed arguments at [ebp+x]. (If you don't know what I'm talking about, read some asm-related tuts. There once was a very good thread covering this topic on woodmanns/fravias board. This tut is already getting too long anyway...). We find the correct argument at [ebp+0C]. Therefore the right instruction is: 00401407 52 push edx 00401408 8B 55 0C mov edx, [ebp+C] OK, the first dword is solved. After having decrypted the string, the program needs to pass the three needed arguments on the stack as shown in the example with the "bruteforce" string. We know the offset of the success string is [ebp+C], and pushing this is a three-byte instruction. Then we need to push the controll id, which is a two byte-instruction. Finally we need to push the handle, which has been passed on the stack together with the encrypted string. We find it at [ebp+8], and it's a three-byte instruction. This is 3 + 2 + 3 = 8 bytes = 2 dwords - BINGO! 0040143B FF 75 0C push dword ptr [ebp+c] 0040143E 6A 03 push 3 00401440 FF 75 08 push dword ptr [ebp+8] We trace this in Softice and adjust the memory accordingly - and it works! Now the main work has been done, we "only" need to bruteforce the right combination. We have: address before after xor ---------------------------------------------------- 401407 EB 3F 90 90 --> 52 8B 55 0C B9 B4 C5 9C --> (a) 40143B 04 66 E7 BB --> FF 75 0C 6A FB 13 EB D1 --> (b) 40143F 4D BD 08 8B --> 03 FF 75 08 4E 42 7D 83 --> (c) These are the values of our three variables a, b and c. After xoring them with the corresponding addresses 401407, 40143B and 40143F we get the right opcodes to have the success message displayed. In the messageboard of Dettens page he gives us the first two keys: 79. Otherwise the bruteforcing might take too long. One thing to remember: All calculations take place in registers, thats why all the dwords from memory must be in reverse order (little endian). Serial: 79DE624C4B ****************** --------------------------------------------------------------------------- --------------------------------------------------------------------------- Here's the source code of my bruteforcer in c (calculation only): void ThreadProc (PVOID pvoid) { char szSerial[11] = ""; int i, iVarA, iVarB, iVarC, iVarTemp, iSerial[10]; volatile PPARAMS pparams; pparams = (PPARAMS) pvoid; // bruteforce serial for (iSerial[0] = 7; iSerial[0] <= 7; iSerial[0]++) { for (iSerial[1] = 9; iSerial[1] <= 9; iSerial[1]++) { for (iSerial[2] = 1; iSerial[2] <= 15; iSerial[2]++) { for (iSerial[3] = 1; iSerial[3] <= 15; iSerial[3]++) { for (iSerial[4] = 1; iSerial[4] <= 15; iSerial[4]++) { for (iSerial[5] = 1; iSerial[5] <= 15; iSerial[5]++) { for (iSerial[6] = 1; iSerial[6] <= 15; iSerial[6]++) { for (iSerial[7] = 1; iSerial[7] <= 15; iSerial[7]++) { for (iSerial[8] = 1; iSerial[8] <= 15; iSerial[8]++) { for (iSerial[9] = 1; iSerial[9] <= 15; iSerial[9]++) { iVarA = 0xDEAD; iVarB = 0xDEAD; iVarC = 0x42424242; for (i = 0; i < 10; i++) { switch (iSerial[i]) { case 1: iVarC += 0x54B; iVarB *= iVarA; iVarA ^= iVarC; break; case 2: iVarC = iVarC - 0x233 + iVarA; iVarB = (iVarB * 0x14) & iVarA; break; case 3: iVarA += 0x582; iVarC *= 0x16; iVarB ^= iVarA; break; case 4: iVarA &= iVarB; iVarB -= 0x111222; iVarC ^= iVarA; break; case 5: if (iVarC != 0) { iVarB -= (iVarA % iVarC); iVarA /= iVarC; iVarA += iVarC; } break; case 6: iVarA ^= iVarC; iVarB &= iVarA; iVarC += 0x546879; break; case 7: iVarC -= 0x25FF5; iVarB ^= iVarC; iVarA += 0x401000; break; case 8: iVarA ^= iVarC; iVarB *= 0x14; iVarC += 0x12589; break; case 9: iVarA -= 0x542187; iVarB -= iVarA; iVarC ^= iVarA; break; case 10: if (iVarB != 0) { iVarTemp = iVarA % iVarB; iVarA /= iVarB; iVarB += iVarTemp; iVarA *= iVarTemp; iVarC ^= iVarTemp; } break; case 11: iVarB += 0x1234FE; iVarC += 0x2345DE; iVarA += 0x9CA4439B; break; case 12: iVarA ^= iVarB; iVarB -= iVarC; iVarC *= 0x12; break; case 13: iVarA &= 0x12345678; iVarC -= 0x65875; iVarB *= iVarC; break; case 14: iVarA ^= 0x55555; iVarB -= 0x587351; break; case 15: iVarA += iVarB; iVarB += iVarC; iVarC += iVarA; break; } } // stop thread if serial ok if ((iVarA == 0x9CC5B4B9) && (iVarB == 0xD1EB13FB) && (iVarC == 0x837D424E)) { for (i = 0; i < 10; i++) { if (iSerial[i] <= 9) { szSerial[i] = iSerial[i] + 0x30; } else { szSerial[i] = iSerial[i] + 0x37; } } SendMessageA (pparams->hWnd, WM_USER, 0, (LPARAM) (LPCTSTR) szSerial); _endthread (); return; } // stop thread if stop button pressed if (!pparams->bContinue) { SendMessageA (pparams->hWnd, WM_USER, 0, (LPARAM) (LPCTSTR) NULL); _endthread (); return; } } } } } } } } } } } _endthread (); return; }